#include <iostream>
#include <stdlib.h>
#include <assert.h>
#include <strings.h>
#include <sstream>
#include "BitSet.h"

/******************************************************************************/
/**                     implementation of class BitSet                       **/
/******************************************************************************/

BitSet::BitSet(size_t   _size):m_bitSet(BitSet::CalcVecSize(_size),0),m_size(_size){}

inline  size_t  BitSet::CalcVecSize(size_t  _bits)
{
    size_t  temp = _bits/BitsInWord;

    if(_bits%BitsInWord)
    {
        ++temp;
    }

    return  temp;
}

void BitSet::Bzero()
{
    for(BitIter it = m_bitSet.begin();it!=m_bitSet.end();++it)
    {
        *it = 0;
    }
}

void    BitSet::Print()
{
    for(size_t i=0;i<m_size;i++)
    {
        std::cout<<bool(operator[](i));
    }
    std::cout<<std::endl<<std::endl;

}

bool    BitSet::Get(size_t  _index)const
{
    assert(_index<m_size);//if index is bigger then bitset size

    return (m_bitSet[_index/BitsInWord] & 1<<(_index%BitsInWord) );
}

void BitSet::Set(size_t  _index,bool _value)
{
    assert(_index<m_size);//if index is bigger then bitset

    if(_value==true)
    {
        m_bitSet[_index/BitsInWord] |= 1<<(_index%BitsInWord);
        return;
    }
    m_bitSet[_index/BitsInWord]&=(mask^(1<<(_index%BitsInWord)));
}

BitSet::BitRef  BitSet::operator[](size_t   _index)
{
    assert(_index<m_size);//if index is bigger then bitset size

    return BitRef(*this,_index);
}

bool BitSet::ShiftBoundChekout(size_t _size)
{
    if(!_size)
    {
        return true;
    }

    if(_size>m_size)
    {
        Bzero();

        return  true;
    }

    return  false;
}

BitSet  BitSet::operator<<(size_t   _offset)
{

    BitSet  temp(*this);

    if(temp.ShiftBoundChekout(_offset) )
    {
        return  temp;
    }

    size_t i=m_size-1 , j=m_size-1;

    for( ;j > m_size-_offset-1;--j)//init to zero last  _offset bits
    {
        temp[j] = 0;
    }

    for(;i>_offset-1;--i,--j)//copy all bits from position last _offset
    {
        temp[j] = operator[](i);
    }

    return temp;
}

BitSet  BitSet::operator>>(size_t   _offset)
{
    BitSet  temp(*this);
    size_t i=0 , j=0;

    if(temp.ShiftBoundChekout(_offset) )
    {
        return  temp;
    }

    for(;j<_offset;++j)
    {
        temp[j] = 0;
    }

    for( ;j < m_size;++j,++i)
    {
        temp[j] = operator[](i);
    }
    return temp;
}

BitSet  BitSet::operator~()
{
    BitSet  temp(*this);


    for(BitIter it = temp.m_bitSet.begin();it!=temp.m_bitSet.end();++it)
    {
        *it ^= mask;
    }
    return  temp;
}



BitSet BitSet::DoBitSetOpeation( BitSet& _other,BitSet::DoFunc _func)
{
    BitIter thisIt = m_bitSet.begin();
    BitIter OtherIt = _other.m_bitSet.begin();

    for(;OtherIt !=_other.m_bitSet.end() && thisIt !=m_bitSet.end();++thisIt,++OtherIt)
    {
        *thisIt = _func(*thisIt,*OtherIt);
    }

    return *this;
}

Word    BitSet::DoAssign(Word& _this,Word& _other)
{
    return (_this = _other);
}

Word    BitSet::DoABitWiseAnd(Word& _this,Word& _other)
{
    return(_this & _other );
}

Word    BitSet::DoABitWiseOr(Word& _this,Word& _other)
{
    return(_this | _other );
}

Word    BitSet::DoABitWiseXor(Word& _this,Word& _other)
{
    return(_this^_other );
}



BitSet  BitSet::operator=( BitSet& _other)
{
    Bzero();

    return ((Word (BitSet::*)(Word&,Word&))BitSet::DoBitSetOpeation(_other,&BitSet::DoAssign));

}
/*
BitSet  BitSet::operator&(const BitSet& _other)
{
    Bzero();

    BitIter thisIt = m_bitSet.begin();
    BitIter OtherIt = _other.m_bitSet.begin();

    for(;OtherIt !=_other.m_bitSet.end() && thisIt !=m_bitSet.end();++thisIt,++OtherIt)
    {
        *thisIt = *OtherIt;
    }

    return *this;
}

BitSet  BitSet::operator=( BitSet& _other)
{
    Bzero();

    BitIter thisIt = m_bitSet.begin();
    BitIter OtherIt = _other.m_bitSet.begin();

    for(;OtherIt !=_other.m_bitSet.end() && thisIt !=m_bitSet.end();++thisIt,++OtherIt)
    {
        *thisIt = *OtherIt;
    }

    return *this;
}

BitSet  BitSet::operator=( BitSet& _other)
{
    Bzero();

    BitIter thisIt = m_bitSet.begin();
    BitIter OtherIt = _other.m_bitSet.begin();

    for(;OtherIt !=_other.m_bitSet.end() && thisIt !=m_bitSet.end();++thisIt,++OtherIt)
    {
        *thisIt = *OtherIt;
    }

    return *this;
}

BitSet  BitSet::operator=( BitSet& _other)
{
    Bzero();

    BitIter thisIt = m_bitSet.begin();
    BitIter OtherIt = _other.m_bitSet.begin();

    for(;OtherIt !=_other.m_bitSet.end() && thisIt !=m_bitSet.end();++thisIt,++OtherIt)
    {
        *thisIt = *OtherIt;
    }

    return *this;
}

        BitSet  ;
        BitSet  operator|(const BitSet& _other);
        BitSet  operator^(const BitSet& _other);*/
/*BitSet  BitSet::operator&(const BitSet& _other)*/


/******************************************************************************/
/**                     implementation of class BitRef                       **/
/******************************************************************************/
BitSet::BitRef::BitRef(BitSet& _bitSet,size_t _index):m_bitSet(_bitSet),m_index(_index){}

BitSet::BitRef::operator  bool()
{
    return  m_bitSet.Get(m_index);
}

 BitSet::BitRef&  BitSet::BitRef::operator=(bool  _to)
{
    m_bitSet.Set(m_index,_to);

    return *this;
}
BitSet::BitRef&  BitSet::BitRef::operator=(const BitRef&  _to)
{
   operator=(bool(const_cast<BitSet::BitRef&>(_to)));
    //m_index = _to.m_index;

    return *this;
}
